package com.guli.gulimall.authserver.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.guli.common.constant.AuthServerConstant;
import com.guli.common.utils.HttpUtils;
import com.guli.common.utils.R;
import com.guli.gulimall.authserver.feign.MemberFeignService;
import com.guli.common.vo.MemberResponseVo;
import com.guli.gulimall.authserver.vo.SocialUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * 处理社交登录请求
 */
@Controller
@Slf4j
public class OAuth2Controller {

    @Value("${oauth2.gitee.client_id}")
    private String client_id;
    @Value("${oauth2.gitee.redirect_uri}")
    private String redirect_uri;
    @Value("${oauth2.gitee.client_secret}")
    private String client_secret;
    @Value("${oauth2.gitee.oAuthTokenHost}")
    private String oAuthTokenHost;
    @Value("${oauth2.gitee.oAuthTokenPath}")
    private String oAuthTokenPath;
    @Value("${oauth2.gitee.userApiHost}")
    private String userApiHost;
    @Value("${oauth2.gitee.userApiPath}")
    private String userApiPath;


    @Autowired
    MemberFeignService memberFeignService;

    @GetMapping("/oauth2.0/gitee/success")
    public String gitee(@RequestParam("code") String code, HttpSession session, HttpServletResponse servletResponse) throws Exception {
        //组装认证请求
        Map<String, String> map = new HashMap<>();
        map.put("grant_type", "authorization_code");
        map.put("code", code);
        map.put("client_id", client_id);
        map.put("redirect_uri", redirect_uri);
        map.put("client_secret", client_secret);

        HttpResponse response = HttpUtils.doPost(oAuthTokenHost, oAuthTokenPath, "post", new HashMap<>(), new HashMap<>(), map);
        if (response.getStatusLine().getStatusCode() == 200) {
            //获取access_token
            String oauthTokenJson = EntityUtils.toString(response.getEntity());
            SocialUser socialUser = JSON.parseObject(oauthTokenJson, SocialUser.class);//access_token
            Map<String, String> query = new HashMap<>();
            query.put("access_token", socialUser.getAccess_token());
            HttpResponse responseUser = HttpUtils.doGet(userApiHost, userApiPath, "get", new HashMap<>(), query);
            if (responseUser.getStatusLine().getStatusCode() == 200) {
                //查询用户成功
                String userStr = EntityUtils.toString(responseUser.getEntity());
                JSONObject userJson = JSON.parseObject(userStr);
                String uid = userJson.getString("id");
                String name = userJson.getString("name");
                socialUser.setUid(uid);//用户ID
                socialUser.setNick_name(name);//昵称
                //当前用户如果是第一次登录，就自动注册（为当前用户生成一个会员信息账号，以后这个社交帐号就对应指定的会员）
                //判断登录或者注册
                R aouthlogin = memberFeignService.aouthlogin(socialUser);
                if (aouthlogin.getCode() == 0) {
                    //社交登录成功
                    MemberResponseVo memberResp = aouthlogin.getData("data", new TypeReference<MemberResponseVo>() {
                    });
                    log.info("登录成功，用户信息:{}", memberResp.toString());
                    /**
                     * session共享问题描述：
                     * 1.（session 使用描述）第一次使用session，命令浏览器保存卡号 jessionid这个cookie，以后浏览器访问哪个网站都会带上这个网站的cookie
                     * 2.（与共享问题）要解决各种域名之间的cookie存储，比如：gulimall.com,auth.gulimall.com,order.gulimall.com
                     * 3.解决方案：发卡的时候将domain指定为最大的父级域名（gulimall.com）,这样一来即使是子域域名也能让父域直接使用
                     *
                     * 集群服务器session问题（集群服务器之间session不共享），多服务session问题（多个服务之间session不共享）
                     *
                     * todo 自己写代码相当复杂，直接使用 SpringSession框架 来解决这个问题。
                     *
                     */
                    //1.默认发的令牌 key=JESSIONID ,作用域是当前域，要解决子域session共享问题(子域放大)
                    //2.使用json序列化方式将序列化的对象数据存储到redis（方便查看）
                    session.setAttribute(AuthServerConstant.LOGIN_USER,memberResp);

                    return "redirect:http://gulimall.com";
                } else {
                    //社交登录失败
                    return "redirect:http://auth.gulimall.com/login.html";
                }
            } else {
                //失败
                return "redirect:http://auth.gulimall.com/login.html";
            }
        } else {
            //授权失败，重定向登录页
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }
}
